package cn.qingfeng.a005_rpc.protocol;

import com.google.gson.*;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

public interface Serializer {
    <T> T deserialize(Class<T> clazz, byte[] bytes);

    <T> byte[] serialize(T obj);

    enum Algorithm implements Serializer {
        Java {
            @Override
            public <T> T deserialize(Class<T> clazz, byte[] bytes) {
                try {
                    return clazz.cast(new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject());
                } catch (IOException | ClassNotFoundException e) {
                    throw new RuntimeException("反序列化失败", e);
                }
            }

            @Override
            public <T> byte[] serialize(T obj) {
                try {
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
                    ObjectOutputStream oos = new ObjectOutputStream(bos);
                    oos.writeObject(obj);
                    return bos.toByteArray();
                } catch (IOException e) {
                    throw new RuntimeException("序列化失败", e);
                }
            }
        },

        Json {
            @Override
            public <T> T deserialize(Class<T> clazz, byte[] bytes) {
//                Gson gson = new Gson();
                Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new Serializer.ClassCodoc()).create();
                String jsonStr = new String(bytes, StandardCharsets.UTF_8);
                return gson.fromJson(jsonStr, clazz);
            }

            @Override
            public <T> byte[] serialize(T obj) {
//                Gson gson = new Gson();
                Gson gson = new GsonBuilder().registerTypeAdapter(Class.class, new Serializer.ClassCodoc()).create();
                String jsonStr = gson.toJson(obj);
                return jsonStr.getBytes(StandardCharsets.UTF_8);
            }
        }
    }

    /**
     * gson一般用不到这个，只有json中以String.class这样的值做value时才需要用这个
     */
    class ClassCodoc implements JsonSerializer<Class<?>>, JsonDeserializer<Class<?>> {
        @Override
        public Class<?> deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
            try {
                String jsonStr = jsonElement.getAsString();
                return Class.forName(jsonStr);
            } catch (ClassNotFoundException e) {
                throw new JsonParseException(e);
            }
        }

        @Override
        public JsonElement serialize(Class<?> aClass, Type type, JsonSerializationContext jsonSerializationContext) {
            return new JsonPrimitive(aClass.getName());
        }
    }

}
